package com.bungarus.busi;

import com.bungarus.Transfer;
import com.bungarus.codec.protobuf.MessageProtobuf;
import com.bungarus.model.BungarusClientException;
import com.bungarus.model.MessageBuilder;
import com.bungarus.model.MessageType;
import com.bungarus.model.OnlineStatus;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.apache.log4j.Logger;

import java.security.SecureRandom;
import java.util.List;
import java.util.Map;

/**
 * Created by tang on 2018/11/25.
 */
@ChannelHandler.Sharable
public class ProcessMessagesFromAccessHandler extends ChannelInboundHandlerAdapter {
    Logger logger = Logger.getLogger(ProcessMessagesFromAccessHandler.class);

    private final Transfer transfer;

    public ProcessMessagesFromAccessHandler(Transfer transfer) {
        this.transfer = transfer;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if(msg instanceof MessageProtobuf.Message){
            MessageProtobuf.Message message = (MessageProtobuf.Message) msg;
            switch (message.getHeader().getType()) {
                case MessageType.HEARTBEAT_PING:
                    //send back pong
                    ctx.writeAndFlush(MessageBuilder.buildHeartbeatPongMessage(message.getHeader().getId(), message.getHeader().getId2()));
                    break;
                case MessageType.STATUS:
                case MessageType.AUTH:
                case MessageType.LOGOUT:
                    logger.info("++++++++++ Message received : \n" + message.toString());
                    transferSessionAndStatusMsgToAllBusi(ctx, message);
                    break;
                default:
                    break;
            }
        }
        else {
            super.channelRead(ctx, msg);
        }
    }

    private void transferSessionAndStatusMsgToAllBusi(ChannelHandlerContext ctx, MessageProtobuf.Message message) {
        Map<String, List<InnerClient>> clients = transfer.getInnerClientList();
        List<InnerClient> clientList = clients.get(Transfer.CLUSTER_TAG_BUSI);
        MessageProtobuf.Message statusSyncMsg = MessageBuilder.buildStatusSyncOrBrdMessage(message, MessageType.STATUS_SYNC, OnlineStatus.SYNC);
        MessageProtobuf.Message bMsg = MessageBuilder.buildTransfer2BusiMsg(Transfer.CLUSTER_TAG_BUSI, statusSyncMsg);

        clientList.forEach(baseClient -> {
            try {
                logger.debug("transfer (1)/2 session message to busi: " + message.toString());
                baseClient.sendMessage(bMsg, Transfer.CLUSTER_TAG_BUSI, ctx);
            }
            catch (BungarusClientException e) {
                ctx.fireExceptionCaught(e);
            }
        });

        MessageProtobuf.Message statusBrdMsg = MessageBuilder.buildStatusSyncOrBrdMessage(message, MessageType.STATUS_BRD, OnlineStatus.BRD);
        MessageProtobuf.Message cMsg = MessageBuilder.buildTransfer2BusiMsg(Transfer.CLUSTER_TAG_BUSI, statusBrdMsg);
        //send status to only one busi node to broadcast all members related to the current user
        if(!clientList.isEmpty()) {
            SecureRandom secureRandom = new SecureRandom();
            long random = secureRandom.nextLong();
            long index = Math.abs(random == Long.MIN_VALUE ? Long.MAX_VALUE : random) % clientList.size();
            try {
                logger.debug("transfer (2)/2 session message to busi: " + message.toString());
                clientList.get((int) index).sendMessage(cMsg, Transfer.CLUSTER_TAG_BUSI, ctx);
            }
            catch (BungarusClientException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
    }
}
